<?php


namespace app\common\service\pay;

use Alipay\EasySDK\Kernel\Config;
use Alipay\EasySDK\Kernel\Factory;
use Alipay\EasySDK\Kernel\Util\ResponseChecker;
use app\model\Order;
use app\model\System;
use think\facade\Log;

class AlipayService {

    private array $system;

    // 异步通知地址
    private string $notifyUrl = '';

    //创建静态私有的变量保存该类对象
    private static ?AlipayService $instance = null;

    //防止使用new直接创建对象
    private function __construct(){

//        $this->merchantPrivateKeyFilePath = 'file://'.base_path().'cert/apiclient_key.pem';

        $this->system = System::getSystem();

        $this->notifyUrl = request()->domain() . '/api/public/alipayNotify';

        // 支付宝配置
        Factory::setOptions($this->getOptions());



    }

    //防止使用clone克隆对象
    private function __clone(){}

    static public function getInstance(): AlipayService
    {
        //判断$instance是否是Singleton的对象，不是则创建
        if (!self::$instance instanceof self) {
            self::$instance = new self();
        }
        return self::$instance;
    }


    private function getOptions(): Config
    {
        $options = new Config();
        $options->protocol = 'https';
        $options->gatewayHost = 'openapi.alipay.com';
        $options->signType = 'RSA2';

        $options->appId = $this->system['alipay_app_id'];

        // 为避免私钥随源码泄露，推荐从文件中读取私钥字符串而不是写入源码中
        // <-- 请填写您的应用私钥，例如：MIIEvQIBADANB ... ... -->
        $options->merchantPrivateKey = $this->system['alipay_merchant_private_key'];

        if ($this->system['alipay_is_cert']){   // 是否使用证书模式

//            <-- 请填写您的支付宝公钥证书文件路径，例如：/foo/alipayCertPublicKey_RSA2.crt -->
            $options->alipayCertPath = $this->system['alipay_cert_path'];
//            <-- 请填写您的支付宝根证书文件路径，例如：/foo/alipayRootCert.crt" -->
            $options->alipayRootCertPath = $this->system['alipay_root_cert_path'];
//            <-- 请填写您的应用公钥证书文件路径，例如：/foo/appCertPublicKey_2019051064521003.crt -->
            $options->merchantCertPath = $this->system['alipay_merchant_cert_path'];

        }else{
            //注：如果采用非证书模式，则无需赋值上面的三个证书路径，改为赋值如下的支付宝公钥字符串即可
//            <-- 请填写您的支付宝公钥，例如：MIIBIjANBg... -->
             $options->alipayPublicKey = $this->system['alipay_public_key'];
        }

        Log::info("------notifyUrl:".$this->notifyUrl."-----------");

        //可设置异步通知接收服务地址（可选）
        $options->notifyUrl = $this->notifyUrl;

        //可设置AES密钥，调用AES加解密相关接口时需要（可选）
//        <-- 请填写您的AES密钥，例如：aa4BtZ4tspm2wnXLb1ThQA== -->
        $options->encryptKey = "";


        return $options;
    }


    /**
     * APP支付
     * @param Order $order
     * @param $notifyUrl
     * @return array|string
     */
    public function app(Order $order, $notifyUrl=''){

        try {

            $fac = Factory::payment()->app();
            //2. 发起API调用（以支付能力下的统一收单交易创建接口为例）
            if ($notifyUrl){    // 独立的异步通知地址
                $fac = $fac->asyncNotify($notifyUrl);
            }
            $result = $fac->pay($order->title, $order->code, $order->amount);
            $responseChecker = new ResponseChecker();
            //3. 处理响应或异常
            if ($responseChecker->success($result)) {
                return makeSuccessResult($result);
            } else {
                return makeErrorResult("调用失败，原因：". $result->msg."，".$result->subMsg.PHP_EOL);
            }
        } catch (\Exception $e) {
            return makeErrorResult("调用失败，". $e->getMessage(). PHP_EOL);
        }

    }

    public function query(Order $order){
        try {
            $result = Factory::payment()->common()->query($order->code);
            $responseChecker = new ResponseChecker();
            //3. 处理响应或异常
            if ($responseChecker->success($result)) {
                return makeSuccessResult($result);
            } else {
                return makeErrorResult("调用失败，原因：". $result->msg."，".$result->subMsg.PHP_EOL);
            }
        } catch (\Exception $e) {
            return makeErrorResult("调用失败，". $e->getMessage(). PHP_EOL);
        }
    }

    public function notify($params){

        try {
            Log::info("------------------------------支付宝支付-------------------------------------");
            Log::info(json_encode($params));

            // 验签
            $result = Factory::payment()->common()->verifyNotify($params);
            if ($result !== true){
                Log::info("----验签失败---".json_encode($result));
                return makeErrorResult($result);
            }

            Log::info("-----验签成功-----");

            // 验证订单
            $order = Order::where('code', $params['out_trade_no'])->where('amount', $params['total_amount'])->find();
            if (!$order){
                return makeErrorResult("订单错误");
            }

            Log::info("-----验证订单成功-----");

            // 验证seller_id
            if ($this->system['alipay_pid'] != $params['seller_id']){
                return makeErrorResult("支付宝账号错误");
            }

            Log::info("-----验证支付宝账号成功-----");

            // 验证appid
            if ($this->system['alipay_app_id'] != $params['app_id']){
                return makeErrorResult("appid错误");
            }
            Log::info("-----验证appid成功-----");

            //
            if($params['trade_status'] == 'TRADE_SUCCESS' || $params['trade_status'] == 'TRADE_FINISHED'){     //  交易成功

                Log::info("-----进入交易成功状态-----");

                // 如果订单未支付，修改订单状态为已支付
                if($order->order_status == 1){
                    $order->order_status = 2;
                    $order->pay_type = 2;
                    $order->out_trade_no = $params['trade_no'];
                    $order->pay_time = $params['gmt_payment'];
                    $order->save();
                }

                Log::info("----修改订单成功-----");

                // 成功
                return makeSuccessResult("success");
            }

            return makeSuccessResult();


        } catch (\Exception $e){
            Log::info("----代码错误----".$e->getMessage(). PHP_EOL);
            return makeErrorResult("调用失败，". $e->getMessage(). PHP_EOL);
        }



    }




}
